package com.smedi.ismedi.cronjob.core.domain.service.impl;

import com.smedi.ismedi.cronjob.core.domain.aggregatemodel.JobInfo;
import com.smedi.ismedi.cronjob.core.domain.repository.JobInfoRepository;
import com.smedi.ismedi.cronjob.core.domain.service.JobInfoDomainService;
import com.smedi.ismedi.cronjob.core.domain.service.JobService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Set;

@Service
@Slf4j
@AllArgsConstructor
public class JobInfoDomainServiceImpl implements JobInfoDomainService {
    private JobInfoRepository cronjobRepository;

    private SchedulerFactoryBean schedulerFactoryBean;

    private JobService jobService;

    @Override
    public Boolean runJob(JobInfo jobInfo) {
        JobInfo job = cronjobRepository.doGet(jobInfo.getId());

        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        try {
            JobDataMap map = jobService.getJobDataMap(jobInfo);
            JobDetail jobDetail = jobService.getJobDetail(jobService.getJobKey(jobInfo), jobInfo.getDescription(), map);
            scheduler.scheduleJob(jobDetail, jobService.getTrigger(jobInfo));
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return true;
    }

    @Override
    public Boolean pauseJob(JobInfo jobInfo) {
        JobInfo job = cronjobRepository.doGet(jobInfo.getId());

        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        try {
            scheduler.pauseJob(jobService.getJobKey(job));
            job.setPause(true);
        } catch (Exception e) {
            e.printStackTrace();
//            throw LogicException.raise(ErrorEnum.NORMAL_ERROR);
        }
        return true;
    }

    @Override
    public Boolean resumeJob(JobInfo jobInfo) {
        JobInfo job = cronjobRepository.doGet(jobInfo.getId());

        Scheduler scheduler = schedulerFactoryBean.getScheduler();

        try {
            scheduler.resumeJob(jobService.getJobKey(job));
            job.setPause(false);
        } catch (Exception e) {
            e.printStackTrace();
//            throw LogicException.raise(ErrorEnum.NORMAL_ERROR);
        }

        return true;
    }

    @Override
    public Boolean refreshJob(JobInfo jobInfo) {
        JobInfo job = cronjobRepository.doGet(jobInfo.getId());

        JobKey jobKey = jobService.getJobKey(job);

        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        try {
            scheduler.pauseJob(jobKey);
            scheduler.unscheduleJob(TriggerKey.triggerKey(jobKey.getName(), jobKey.getGroup()));
            scheduler.deleteJob(jobKey);
            JobDataMap map = jobService.getJobDataMap(job);
            JobDetail jobDetail = jobService.getJobDetail(jobKey, job.getDescription(), map);
            scheduler.scheduleJob(jobDetail, jobService.getTrigger(job));
        } catch (Exception e) {
            log.error(e.getMessage());
            e.printStackTrace();
//            throw LogicException.raise(ErrorEnum.NORMAL_ERROR);
        }
        return true;
    }

    @Override
    public List<JobInfo> restartAllJob() {
        List<JobInfo> cronjobs = jobService.findAll();
        synchronized (log) {                                                         //只允许一个线程进入操作
            Scheduler scheduler = schedulerFactoryBean.getScheduler();
            try {
                Set<JobKey> set = scheduler.getJobKeys(GroupMatcher.anyGroup());
                scheduler.pauseJobs(GroupMatcher.anyGroup());                               //暂停所有JOB
                for (JobKey jobKey : set) {                                                 //删除从数据库中注册的所有JOB
                    scheduler.unscheduleJob(TriggerKey.triggerKey(jobKey.getName(), jobKey.getGroup()));
                    scheduler.deleteJob(jobKey);
                }

                for (JobInfo job : cronjobs) {                               //从数据库中注册的所有JOB
                    log.info("Job register name : {} , group : {} , cron : {}", job.getName(), job.getJobGroup(), job.getCronExpression());
                    JobDataMap map = jobService.getJobDataMap(job);
                    JobKey jobKey = jobService.getJobKey(job);
                    JobDetail jobDetail = jobService.getJobDetail(jobKey, job.getDescription(), map);
                    if (!job.getPause()) {
                        scheduler.scheduleJob(jobDetail, jobService.getTrigger(job));
                    } else {
                        log.info("Job jump name : {} , Because {} status is {}", job.getName(), job.getName(), job.getPause());
                    }
                }
            } catch (Exception e) {
                log.error(e.getMessage());
                e.printStackTrace();
//                throw LogicException.raise(ErrorEnum.NORMAL_ERROR);
            }
        }
        return cronjobs;
    }

    @Override
    public JobInfo insertJob(JobInfo jobInfo) {
//        if (!CronExpression.isValidExpression(jobInfo.getCronExpression())) {
//            throw LogicException.raise(ErrorEnum.CRON_FORMAT_ERROR);
//        }

        JobKey jobKey = jobService.getJobKey(jobInfo);
        TriggerKey triggerKey = new TriggerKey(jobKey.getName(), jobKey.getGroup());
        Scheduler scheduler = schedulerFactoryBean.getScheduler();

        try {
            jobInfo = cronjobRepository.doInsert(jobInfo);
            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(jobInfo.getCronExpression());

            CronTrigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity(jobKey.getName(), jobKey.getGroup())
                    .withSchedule(cronScheduleBuilder)
                    .usingJobData(jobService.getJobDataMap(jobInfo))
                    .build();

            scheduler.rescheduleJob(triggerKey, trigger);

        } catch (Exception e) {
            e.printStackTrace();
//            throw LogicException.raise(ErrorEnum.NORMAL_ERROR);
        }

        return jobInfo;
    }

    @Override
    public boolean deleteJob(JobInfo jobInfo) {
        JobInfo job = cronjobRepository.doGet(jobInfo.getId());
        try {
            Scheduler scheduler = schedulerFactoryBean.getScheduler();

            TriggerKey triggerKey = jobService.getTrigger(job).getKey();

            scheduler.pauseTrigger(triggerKey);

            scheduler.unscheduleJob(triggerKey);

            scheduler.deleteJob(jobService.getJobKey(job));
        } catch (Exception e) {
            e.printStackTrace();
//            throw LogicException.raise(ErrorEnum.NORMAL_ERROR);
        }
        return cronjobRepository.doDelete(jobInfo.getId());
    }

    @Override
    public JobInfo updateJob(JobInfo jobInfo) {
        JobInfo job = cronjobRepository.doGet(jobInfo.getId());

        Scheduler scheduler = schedulerFactoryBean.getScheduler();

        try {
            TriggerKey triggerKey = jobService.getTrigger(job).getKey();
            scheduler.pauseTrigger(triggerKey);
            scheduler.unscheduleJob(triggerKey);
            scheduler.deleteJob(jobService.getJobKey(job));

            JobDataMap map = jobService.getJobDataMap(jobInfo);
            JobDetail jobDetail = jobService.getJobDetail(jobService.getJobKey(jobInfo), jobInfo.getDescription(), map);
            scheduler.scheduleJob(jobDetail, jobService.getTrigger(jobInfo));
        } catch (Exception e) {
            log.error(e.getMessage());
//            throw LogicException.raise(ErrorEnum.NORMAL_ERROR);
        }
        return cronjobRepository.doUpdate(jobInfo);
    }

    @Override
    public JobInfo getJob(Long id) {
        return cronjobRepository.doGet(id);
    }

    @Override
    public List<JobInfo> listJob(JobInfo jobInfo) {
        return cronjobRepository.doList();
    }
}
